﻿using System;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Forms;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
using Groove.Core.Cache;
using Groove.Core.Infrastructure;
using Groove.Core.MediaFile;
using Groove.Core.Player;
using SchwabenCode.QuickIO;
using MouseEventArgs = System.Windows.Input.MouseEventArgs;

namespace Groove.Wpf
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        private string _musicFolder;
        private string CacheFilePath => AppDomain.CurrentDomain.BaseDirectory + "cache.json";

        private readonly WindowViewModel _windowViewModel = new WindowViewModel();

        private int _previousVolumn;

        private IMediaFile _previousSong;

        private bool _isIngoreCursorPosition;

        private IPlayerEngine _player;

        public MainWindow()
        {
            InitializeComponent();
            Loaded += MainWindow_Loaded;
            Closing += MainWindow_Closing;
            Closed += MainWindow_Closed;
            Playlist.SelectionChanged += Playlist_SelectionChanged;
            _windowViewModel.AlbumCover = new BitmapImage(new Uri("pack://application:,,,/Groove.Wpf;component/Resources/Tape.jpg"));
            DataContext = _windowViewModel;
        }

        #region Windows Events
        private void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            InitPlayer();
            LoadCache();
        }

        private void MainWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            _player.ShutDown();
        }

        private void MainWindow_Closed(object sender, EventArgs e)
        {
            SaveCache();
        }

        private void OnClose(object sender, MouseButtonEventArgs e)
        {
            Close();
        }

        private void OnMinimum(object sender, MouseButtonEventArgs e)
        {
            WindowState = WindowState.Minimized;
        }
        private void TitleMouseDown(object sender, MouseButtonEventArgs e)
        {
            DragMove();
        }
        #endregion

        #region Music Library Cache
        private void LoadCache()
        {
            if (!QuickIOFile.Exists(CacheFilePath)) return;
            var jsonStr = QuickIOFile.ReadAllText(CacheFilePath);
            if (string.IsNullOrEmpty(jsonStr)) return;
            var playerCache = jsonStr.DeserializeJsonObject<PlayerCache>();
            if (playerCache == null || playerCache.IsEmpty)
            {
                return;
            }
            UpdateMusicFolder(playerCache.MusicFolder);
        }

        private void SaveCache()
        {
            var playerCache = new PlayerCache()
            {
                MusicFolder = _musicFolder,
                PlayingMediaFileFullPath = _player.CurrentMediaFile?.FullFileName
            };
            var jsonStr = playerCache.ToJsonString();
            if (QuickIOFile.Exists(CacheFilePath)) QuickIOFile.Delete(CacheFilePath);
            QuickIOFile.WriteAllText(CacheFilePath, jsonStr);
        }

        private void MusicOnPC_Clicked(object sender, RoutedEventArgs e)
        {
            var folderBrowerDlg = new FolderBrowserDialog();
            folderBrowerDlg.Description = @"请选择本地音乐目录";
            if (folderBrowerDlg.ShowDialog() != System.Windows.Forms.DialogResult.OK) return;
            UpdateMusicFolder(folderBrowerDlg.SelectedPath);
        }

        private void UpdateMusicFolder(string folder)
        {
            if (string.IsNullOrEmpty(folder)) return;
            _musicFolder = folder;
            var playList = LocalMediaFileFinder.SearchMediaFiles(folder);
            Playlist.ItemsSource = playList;
        }
        #endregion

        #region Player Events
        private void InitPlayer()
        {
            _player = new FMODPlayerEngine();
            _player.Init();
            _player.PositionChanged += Player_PositionChanged;
            _player.PlayNext += PlayNext;
            _player.StateChanged += Player_StateChanged;
        }

        private void Player_StateChanged(object sender, EventArgs e)
        {
            _windowViewModel.IsPlaying = _player.PlayerState == PlayerState.Playing;
        }

        private void PlayNext(object sender, EventArgs e)
        {
            if (_windowViewModel.PlayMode == PlayMode.SingleCycle)
                _player.PlayOrPause();
            else
                Next();
        }
        #endregion

        #region Playlist Events
        private void Playlist_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            // Set Playing state
            if (!(e.AddedItems[0] is IMediaFile item)) return;
            if (e.RemovedItems.Count > 0)
            {
                if (e.RemovedItems[0] is IMediaFile oldItem)
                {
                    _previousSong = oldItem;
                    oldItem.IsPlaying = false;
                }
            }
            item.IsPlaying = true;

            UpdateViewModel(item);

            Play(item);
        }

        private void UpdateViewModel(IMediaFile playingMedia)
        {
            _windowViewModel.Title = playingMedia.Title;
            _windowViewModel.ArtistAndAlbum = $@"{playingMedia.Artists}· {playingMedia.Album}";
            _windowViewModel.MediaTimeMs = (int)playingMedia.Duration.TotalMilliseconds;
            _windowViewModel.CurrentTimeStr = @"00:00";
            _windowViewModel.LeftTimeStr = $@"{playingMedia.Duration.Minutes:D2}:{playingMedia.Duration.Seconds:D2}";
            if (playingMedia.AlbumCover == null)
            {
                _windowViewModel.AlbumCover = new BitmapImage(new Uri("pack://application:,,,/Groove.Wpf;component/Resources/Tape.jpg"));
                return;
            }
            var stream = new MemoryStream();
            playingMedia.AlbumCover.Save(stream, System.Drawing.Imaging.ImageFormat.Png);
            var imageConverter = new ImageSourceConverter();
            _windowViewModel.AlbumCover = (ImageSource)(imageConverter.ConvertFrom(stream));
        }

        private void Play(IMediaFile item)
        {
            _player.CurrentMediaFile = item;
            _player.PlayOrPause();
        } 
        #endregion

        #region Play Control : Play,Pause,Previous,Next
        private void PreviousButton_OnClick(object sender, RoutedEventArgs e)
        {
            Previous();
        }

        private void PlayButton_OnClick(object sender, RoutedEventArgs e)
        {
            _player.PlayOrPause();
        }

        private void PauseButton_OnClick(object sender, RoutedEventArgs e)
        {
            _player.PlayOrPause();
        }

        private void NextButton_OnClick(object sender, RoutedEventArgs e)
        {
            Next();
        }

        private void Previous()
        {
            if (_previousSong == null) return;
            Playlist.SelectedItem = _previousSong;
        }

        private void Next()
        {
            Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
             {
                 if (Playlist.Items.Count < 1) return;
                 if (_windowViewModel.PlayMode == PlayMode.RandomPlay)
                 {
                     var r = new Random(Environment.TickCount);
                     var rIndex = r.Next(0, Playlist.Items.Count - 1);
                     Playlist.SelectedIndex = rIndex;
                     return;
                 }
                 var index = Playlist.SelectedIndex + 1;
                 if (index >= Playlist.Items.Count)
                     index = 0;
                 Playlist.SelectedIndex = index;
             }));
        }
        #endregion

        #region PlayMode Setting
        private void PlayModeButton_OnClick(object sender, RoutedEventArgs e)
        {
            switch (_windowViewModel.PlayMode)
            {
                case PlayMode.ListCycle:
                    _windowViewModel.PlayMode = PlayMode.SingleCycle;
                    break;
                case PlayMode.SingleCycle:
                    _windowViewModel.PlayMode = PlayMode.RandomPlay;
                    break;
                case PlayMode.RandomPlay:
                    _windowViewModel.PlayMode = PlayMode.ListCycle;
                    break;
                default:
                    throw new ArgumentOutOfRangeException();
            }

            SetPlayModeImage();
        }

        private void Part_PlaymodeIcon_MouseEnter(object sender, MouseEventArgs e)
        {
            SetPlayModeImage();
        }

        private void Part_PlaymodeIcon_MouseLeave(object sender, MouseEventArgs e)
        {
            SetPlayModeImage();
        }

        private void SetPlayModeImage()
        {
            var iconCtrl = PlayModeButton.Template.FindName("PlayModeIcon", PlayModeButton) as Image;
            if (iconCtrl == null) return;
            var isMouseHover = PlayModeButton.IsMouseOver;
            var playMode = _windowViewModel.PlayMode;
            switch (playMode)
            {
                case PlayMode.ListCycle:
                    iconCtrl.Source = isMouseHover
                        ? new BitmapImage(new Uri("pack://application:,,,/Groove.Wpf;component/Resources/ListCycleActive.png"))
                        : new BitmapImage(new Uri("pack://application:,,,/Groove.Wpf;component/Resources/ListCycle.png"));
                    break;
                case PlayMode.SingleCycle:
                    iconCtrl.Source = isMouseHover
                        ? new BitmapImage(new Uri("pack://application:,,,/Groove.Wpf;component/Resources/SingleCycleActive.png"))
                        : new BitmapImage(new Uri("pack://application:,,,/Groove.Wpf;component/Resources/SingleCycle.png"));
                    break;
                case PlayMode.RandomPlay:
                    iconCtrl.Source = isMouseHover
                        ? new BitmapImage(new Uri("pack://application:,,,/Groove.Wpf;component/Resources/RandomPlayActive.png"))
                        : new BitmapImage(new Uri("pack://application:,,,/Groove.Wpf;component/Resources/RandomPlay.png"));
                    break;
                default:
                    throw new ArgumentOutOfRangeException();
            }
        }
        #endregion

        #region Volumn Control
        private void VolumnBtnClicked(object sender, RoutedEventArgs e)
        {
            _windowViewModel.IsMute = !_windowViewModel.IsMute;
            if (_windowViewModel.IsMute)
            {
                _previousVolumn = _windowViewModel.Volumn;
                _windowViewModel.Volumn = 0;
            }
            else
            {
                if (_previousVolumn == 0) _previousVolumn = 100;
                _windowViewModel.Volumn = _previousVolumn;
            }
        }

        private void VolumnChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            if (_player == null) return;
            if (_windowViewModel.IsMute)
            {
                if (!_player.IsMuted)
                    _player.Mute(); // Toggle player mute state
            }
            else
            {
                if (_player.IsMuted)
                    _player.Mute(); // Toggle player mute state
                _player.Volumn = _windowViewModel.Volumn;
            }
        } 
        #endregion

        #region Player Position Control
        private void Player_PositionChanged(uint currentposition)
        {
            if (!_isIngoreCursorPosition)
                _windowViewModel.CurrentTimeMs = (int)currentposition;
            var currentDuration = FormatMsToTimeSpan(_windowViewModel.CurrentTimeMs);
            var leftDuration = FormatMsToTimeSpan(_windowViewModel.MediaTimeMs - _windowViewModel.CurrentTimeMs);
            _windowViewModel.CurrentTimeStr = $@"{currentDuration.Minutes:D2}:{currentDuration.Seconds:D2}";
            _windowViewModel.LeftTimeStr = $@"{leftDuration.Minutes:D2}:{leftDuration.Seconds:D2}";
        }

        private TimeSpan FormatMsToTimeSpan(int ms)
        {
            var hour = 0;
            var minute = 0;
            var second = ms / 1000;

            if (second > 60)
            {
                minute = second / 60;
                second %= 60;
            }
            if (minute > 60)
            {
                hour = minute / 60;
                minute %= 60;
            }
            return new TimeSpan(hour, minute, second);
        }

        private void PlayProgress_OnPreviewMouseDown(object sender, MouseButtonEventArgs e)
        {
            var value = (e.GetPosition(PlayProgress).X / PlayProgress.ActualWidth) * (PlayProgress.Maximum - PlayProgress.Minimum);
            _player.PositionMs = (uint)value;
        }

        private void PlayProgress_OnDragStarted(object sender, DragStartedEventArgs e)
        {
            _isIngoreCursorPosition = true;
        }

        private void PlayProgress_OnDragCompleted(object sender, DragCompletedEventArgs e)
        {
            _player.PositionMs = (uint)_windowViewModel.CurrentTimeMs;
            _isIngoreCursorPosition = false;
        }
        #endregion
    }
}
